package org.grottarossa.ui.core.controls.document;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.ResourceBundle;
import java.util.UUID;

import org.grottarossa.template.data.pojo.content.Content;
import org.grottarossa.template.data.pojo.content.Document;
import org.grottarossa.template.data.pojo.content.DocumentList;
import org.grottarossa.ui.core.ApplicationSession;
import org.grottarossa.ui.core.RuntimeVariables;
import org.grottarossa.ui.core.actions.CustomAction;
import org.grottarossa.ui.core.actions.CustomActionHandlerForContextMenu;
import org.grottarossa.ui.core.controls.document.upload.IDocumentUploaderObserver;
import org.grottarossa.ui.core.controls.document.upload.UploadDocument;
import org.grottarossa.ui.core.controls.document.upload.UploadDocumentFactory;

import com.vaadin.ui.Window;


/***
 * Gestisce la logica del controllo per la gestione delle versioni di un documento
 * @author 
 *
 */
public class DocumentVersionsManagerPresenter implements IDocumentUploaderObserver
{
	private final ResourceBundle m_localizer;

	/*** View ***/
	private final DocumentVersionsManager m_view;

	/*** Content di riferimento ***/
	private final Content m_content;

	/*** ID Versione selezionata ***/
	private Integer m_selectedVersion = -1;

	/*** Nome della versione selezionata ***/
	private String m_selectedVersionName;

	/*** Window del popup per il caricamento di una nuova versione ***/
	private Window m_uploadPopup;

	/*** Se = true gestisce la view in modo da poter caricare solo la prima versione del documento ***/
	private final boolean m_firstVersionUploader;

	private final ApplicationSession m_appSession;

	public DocumentVersionsManagerPresenter(ApplicationSession appSession, DocumentVersionsManager view, Content content, ResourceBundle localizer, boolean firstVersionUploader)
	{
		this.m_appSession = appSession;
		this.m_view = view;
		this.m_content = content;
		this.m_localizer = localizer;
		this.m_firstVersionUploader = firstVersionUploader;
		m_view.setPresenter(this);
	}

	public void initialize()
	{
		refreshView();
	}

	/***
	 * Aggiorna il menu delle azioni della tabella in base allo stato corrente
	 */
	private void refreshActionsMenu()
	{
		ArrayList<CustomAction> actions = new ArrayList<CustomAction>();

		DocumentList versions = m_content.getDocumentList();
		boolean existsVersions = (versions != null) && versions.size() > 0;

		if(!m_firstVersionUploader || !existsVersions)
			actions.add(instanceAction(m_localizer.getString("form.actions.upload"), "upload", this));

		if(existsVersions && !m_firstVersionUploader)
		{
			actions.add(instanceAction(m_localizer.getString("form.actions.delete"), "deleteVersion", this));
			actions.add(instanceAction(m_localizer.getString("form.actions.checkout"), "checkOut", this));
			actions.add(instanceAction(m_localizer.getString("form.actions.checkin"), "checkIn", this));
			actions.add(instanceAction(m_localizer.getString("form.actions.download"), "download", this));
		}

		CustomActionHandlerForContextMenu actionsHandler =
			new CustomActionHandlerForContextMenu(true, actions);

		m_view.setTableMenu(actionsHandler);
	}

	/***
	 * Genera una nuova action per il menu della tabella
	 * @param caption
	 * @param method
	 * @param presenter
	 * @return
	 */
	private CustomAction instanceAction(String caption, final String method, final DocumentVersionsManagerPresenter presenter)
	{
		return new CustomAction(caption)
		{
			private String m_method = method;
			private DocumentVersionsManagerPresenter m_presenter = presenter;

			@Override
			public boolean isEnabled(Object target)
			{
				return true;
			}

			@Override
			public void run(Object target)
			{
				Method mthd;

				try
				{

					mthd = DocumentVersionsManagerPresenter.class.getMethod(m_method);
					mthd.invoke(m_presenter);
				}
				catch (Exception e)
				{
					throw new RuntimeException(e.toString());
				}
			}
		};
	}

	/***
	 * Aggiorna la view
	 */
	private void refreshView()
	{
		m_view.fillVersionsTable(m_content.getDocumentList());
		refreshActionsMenu();
	}

	/***
	 * Gestisce il ritorno da un'operazione di upload di una nuova versione
	 */
	public void documentUploaded(String filename)
	{
		try
		{
			refreshView();
			m_view.removePopup(m_uploadPopup);
			m_view.showInfo(m_localizer.getString("form.messages.uploadok"));
		}
		catch(Exception ex)
		{
			m_view.showError(m_localizer.getString("form.messages.uploadko"));
		}
	}

	/***
	 * Elimina la versione selezionata
	 */
	public void deleteVersion()
	{
		try
		{
			m_appSession.getBuilder().getDocumentManagement().removeFile(m_content.getDocumentID(), m_selectedVersion);
			m_view.showInfo(m_localizer.getString("form.messages.deleteok"));
			DocumentList versions = m_appSession.getBuilder().getDocumentManagement().getDocumentVersions(m_content.getDocumentID());
			m_content.setDocumentList(versions);
			refreshView();
		}
		catch(Exception ex)
		{
			m_view.showError(m_localizer.getString("form.messages.deleteko"));
		}
	}

	/***
	 * Esegue il check-out della versione selezionata
	 */
	public void checkOut()
	{
		try
		{
			//Setto la versione del documento sul content per dire al driver a quale versione faccio riferimento
			m_content.setDocumentVersion(m_selectedVersion.toString());

			m_appSession.getBuilder().getDocumentManagement().checkOut(m_content);
			m_view.showInfo(m_localizer.getString("form.messages.checkoutok"));
			refreshView();
		}
		catch(Exception ex)
		{
			m_view.showError(m_localizer.getString("form.messages.checkoutko"));
		}
	}

	/***
	 * Esegue il check-in della versione selezionata
	 */
	public void checkIn()
	{
		uploadNewVersion(true);
	}

	/***
	 * Esegue il download della versione selezionata
	 */
	public void download()
	{
		try
		{
			String docsPath = RuntimeVariables.PSAPV_BasePath + "\\" + RuntimeVariables.PSAPV_DocumentPath;
			String documentName = m_content.getDocumentID().getIdentity().toString() + "_" + m_selectedVersion + "_" + m_selectedVersionName;

			m_content.setFilePath(docsPath);
			m_content.setDocumentVersion(m_selectedVersion.toString());

			File fileObj = new File(docsPath + "\\" + documentName);

			if(!fileObj.exists() || !fileIsValidInCache(fileObj))
			{
				if(fileObj.exists())
					fileObj.delete();

				for(Document d: m_content.getDocumentList())
				{
					if(d.getFileVersion() == m_selectedVersion)
					{
						byte [] bytes = m_appSession.getBuilder().getDocumentManagement().fetchFile(d);

						FileOutputStream fos = null;

						try
						{
							fileObj.createNewFile();
							fos = new FileOutputStream(fileObj);
							fos.write(bytes);
						}
						finally
						{
							if(fos != null)
								fos.close();
						}
					}
				}
			}

			String context = RuntimeVariables.getBaseHttpUrl(RuntimeVariables.hostName, RuntimeVariables.PSAPV_Port, RuntimeVariables.PSAPV_Context);

			m_view.openUrl(context + RuntimeVariables.PSAPV_DownloadDocumentServletName + "?path=" +
					URLEncoder.encode(docsPath + "\\" + documentName, "UTF-8") +
					"&filename=" + URLEncoder.encode(m_selectedVersionName, "UTF-8"));
		}
		catch(Exception ex)
		{
			m_view.showError(m_localizer.getString("form.messages.downloadko"));
		}
	}

	/***
	 * Verifica se il file della cache passato in input � sempre valido o se � scaduto
	 * @param fileObj
	 * @return
	 */
	private boolean fileIsValidInCache(File fileObj)
	{
		Date lastModified = new Date(fileObj.lastModified());
		Date today = new Date();

		if(today.getYear() != lastModified.getYear())
			return false;

		if(today.getMonth() != lastModified.getMonth())
			return false;

		if(today.getDay() != lastModified.getDay())
			return false;

		return true;
	}

	/***
	 * Apre il popup per l'upload di una nuova versione
	 */
	public void upload()
	{
		uploadNewVersion(false);
	}

	/***
	 * Apre il popup per l'upload di una nuova versione
	 * @param checkin Se = true deve eseguire il check-in
	 */
	private void uploadNewVersion(boolean checkin)
	{
		try
		{
			UploadDocumentFactory f = new UploadDocumentFactory(m_appSession, checkin);
			UploadDocument ud = f.create(m_content);
			ud.addObserver(this);
			m_uploadPopup = m_view.showInPopup(ud, 400, 150, m_localizer.getString("form.popups.uploadcaption"), false, true);
		}
		catch(Exception ex)
		{
			m_view.showError(m_localizer.getString("form.messages.downloadko"));
		}
	}

	/***
	 * Memorizza la versione selezionata sul click destro del mouse
	 * @param versionId
	 * @param docName
	 */
	public void rightClickOnItem(Integer versionId, String docName)
	{
		m_selectedVersion = versionId;
		m_selectedVersionName = docName;
	}
}
